package com.example.utility.crypto.sm4;

/**
 * @author 季舟
 * @Date 2024-12-27 17:01
 */
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.security.Security;
import java.util.Base64;

public class SM4Demo {

    /**
     * 静态初始化块，用于在类加载时添加Bouncy Castle加密提供者
     *
     * 添加Bouncy Castle作为安全提供者，以支持后续可能用到的加密、解密等安全操作
     * 这里使用静态初始化块确保类在被加载的时候就添加好提供者，避免重复添加，提高效率
     */
    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 程序的主入口点
     * 本方法演示了如何使用SM4加密算法对明文进行加密和解密
     * @param args 命令行参数
     * @throws Exception 如果加密或解密过程中发生错误，则抛出异常
     */
    public static void main(String[] args) throws Exception {
        // 生成密钥
        SecretKey secretKey = generateKey();
        System.out.println("密钥: " + Base64.getEncoder().encodeToString(secretKey.getEncoded()));

        // 要加密的明文
        String plainText = "Hello, SM4!";
        System.out.println("明文: " + plainText);

        // 加密
        String encryptedText = encrypt(plainText, secretKey);
        System.out.println("密文: " + encryptedText);

        // 解密
        String decryptedText = decrypt(encryptedText, secretKey);
        System.out.println("解密后的明文: " + decryptedText);
    }

    /**
     * 生成SM4加密算法的密钥
     *
     * 该方法使用KeyGenerator类来生成SM4加密算法所需的密钥
     * 密钥长度被初始化为128位，以确保加密的安全性
     *
     * @return SecretKey 生成的SM4加密密钥
     * @throws Exception 如果KeyGenerator的初始化或密钥生成过程中发生错误，则抛出此异常
     */
    public static SecretKey generateKey() throws Exception {
        // 实例化KeyGenerator对象，指定使用SM4加密算法和BC安全提供者
        KeyGenerator keyGenerator = KeyGenerator.getInstance("SM4", "BC");

        // 初始化KeyGenerator，设置密钥长度为128位
        keyGenerator.init(128);

        // 生成并返回SM4加密密钥
        return keyGenerator.generateKey();
    }

    /**
     * 使用SM4算法对明文进行加密
     *
     * @param plainText 明文字符串，代表需要加密的数据
     * @param secretKey 加密密钥，用于加密明文
     * @return 返回加密后的密文字符串
     * @throws Exception 如果加密过程中发生错误，则抛出异常
     */
    public static String encrypt(String plainText, SecretKey secretKey) throws Exception {
        // 创建Cipher对象，指定使用SM4算法，ECB模式和PKCS7Padding填充方式，并使用BC（Bouncy Castle）安全提供者
        Cipher cipher = Cipher.getInstance("SM4/ECB/PKCS7Padding", "BC");

        // 初始化Cipher对象为加密模式，并传入密钥
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);

        // 对明文进行加密，得到加密后的字节数组
        byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());

        // 将加密后的字节数组转换为Base64编码的字符串，以方便传输和存储
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }

    /**
     * 使用SM4算法解密字符串
     *
     * @param encryptedText 加密的字符串，需要被解密
     * @param secretKey 解密使用的密钥，必须与加密时使用的密钥相同
     * @return 解密后的字符串
     * @throws Exception 如果解密过程中发生错误，则抛出异常
     */
    public static String decrypt(String encryptedText, SecretKey secretKey) throws Exception {
        // 创建Cipher对象，用于执行解密操作
        Cipher cipher = Cipher.getInstance("SM4/ECB/PKCS7Padding", "BC");

        // 初始化Cipher对象为解密模式，并传入密钥
        cipher.init(Cipher.DECRYPT_MODE, secretKey);

        // 使用Base64解码器，将加密的字符串解码为字节数组
        byte[] decodedBytes = Base64.getDecoder().decode(encryptedText);

        // 使用Cipher对象，对解码后的字节数组执行解密操作
        byte[] decryptedBytes = cipher.doFinal(decodedBytes);

        // 将解密后的字节数组转换为字符串并返回
        return new String(decryptedBytes);
    }
}

